using UnityEngine;
using System.Collections;
using System;
using System.Diagnostics;

public class Algorithm : MonoBehaviour {
	
	
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
	
	public void GenerateLevel()
	{
		
		Cells = new Cell(MapWidth, MapHeight);
		
		PaintCellRectangle(0,0,MapWidth - 1, MapHeight - 1, new Cell_granite(), true);
		
		PartitionTree = PartitionDungeon();
		
		partitionTree.EnumerateLeafNodes(new AddRoomDelegate(AddRoom));
		
		
	}
	
	private DungeonNode PartitionDungeon()
	{
	
		DungeonNode.Map = this;
		DungeonNode.rand = rand;
		DungeonNode rootNode = new DungeonNode(0.0f, 0.0f, 1.0f, 1.0f);
		rootNode.Partition();
		
		return rootNode;
		
		
	}
	
	
	
	
	
	
	public class DungeonNode
	{
	
		public double LeftEdge;
		public double RightEdge;
		public double TopEdge;
		public double BottomEdge;
		
		public double NodeWidth;
		public double NodeHeight;
		
		private Orientation SplitOrientation;
		
		public double SplitLocation;
		
		public DungeonNode Left{ get; set; }
		public DungeonNode Right { get; set; }
		
		static private double SmallestPartitionSize = .15;
		static private double MaxPartitionSizeRatio = 1.5f;
		static private double HomogenityFactor = 0.25;
		static public Map Map;
		
		private enum Orientation{Horizontal, Vertical};
		public DungeonNode(double startX, double startY, double endX, double endY)
		{
		
			LeftEdge = startX;
			RightEdge = endX;
			TopEdge = startY;
			BottomEdge = endY;
			
			NodeWidth = RightEdge - LeftEdge;
			NodeHeight = BottomEdge - TopEdge;
			
		}
		
		public void Partition()
		{
			if(NodeWidth / NodeHeight > MaxPartitionSizeRatio)
				SplitOrientation = Orientation.Horizontal;
			else if(NodeHeight/ NodeWidth > MaxPartitionSizeRatio)
				SplitOrientation = Orientation.Vertical;
			else SplitOrientation = (r.Next(2) == 1) ? Orientation.Horizontal : 
				Orientation.Vertical;
			if(SplitOrientation == Orientation.Horizontal)
			{
			
				SplitLocation = LeftEdge + HomogenizedRandomValue() * NodeWidth;
				
				Left = new DungeonNode(LeftEdge, TopEdge, SplitLocation, BottomEdge);
				Right = new DunbeonNode(SplitLocation, TopEdge, RightEdge, BottomEdge);
				
				if(WeShouldSplit(SplitLocation - LeftEdge))
					Left.Partition();
				if(WeShouldSplit(RightEdge - SplitLocation))
					Right.Partition();
				
			}
			else
			{
				SplitLocation = TopEdge + HomogenizedRandomValue() * NodeHeight;
				
				Left = new DungeonNode(LeftEdge, TopEdge, RightEdge, SpliLocation);
				Right = new DungeonNode(LeftEdge, SplitLocation, RightEdge, BottomEdge);
				
				if(WeShouldSplit(SplitLocation - TopEdge))
					Left.Partition();
				if(WeShouldSplit(BottomEdge - SplitLocation))
					Right.Partition();				
			}
			
		}
		
		private bool WeShouldSplit(double partitionSize)
		{
			
			if(partitionSize > SmallestPartitionSize && partitionSize 
			   < SmallestPartitionSize * 2.0 && r.NextDouble() <= .1)
				return false;
			
				return partitionSize > SmallestPartitionSize;
		}
		private double HomgenizedRandomValue()
		{
			return 0.5 - (r.NextDouble() * HomgenityFactor);
		}
		public void EnumerateLeafNodes(AddRoomDelegate addRoomDelegate)
		{
			if(Left != null || Right != null)	
			{
			
				if(Left != null)
					Left.EnumerateLeafNodes(addRoomDelegate);
				if(Right != null)
					Right.EnumerateLeafNodes(addRoomDelegate);
			}
			else
				addRoomDelegate(LeftEdge, TopEdge, RightEdge, BottomEdge);
		}
		
		public void Render(Graphics gr)
		{
		
			float w = Map.MapWidth * 8;
			float.h = Map.MapHeight * 8;
			gr.FillRectangle(Brushes.Black, (float)LeftEdge * w + 10, (float)TopEdge
* h + 10, (float)(RightEdge - LeftEdge) * w, (float)(BottomEdge - TopEdge) * h);
			gr.DrawRectangle(Pens.Blue, (float)LeftEdge * w + 10, (float)TopEdge * h
+ 10, (float)(RightEdge - LeftEdge) * w, (float)(BottomEdge - TopEdge) * h);
			
			if(Left != null)
				Left.Redner(gr);
			if(Right != null)
				Right.Render(gr);
		}
		
	}
		

		public void SquareRoomGenerator(DungeonNode dungeonRegion)	
	{
		int MinIdealRoomSize = 4;
		
		int xRegionStart = (int)Math.Ceiling((dungeonREgion.LeftEdge * (MapWidth -1)));
		int yRegionStart = (int)Math.Ceiling((dungeonREgion.TopEdge * (MapHeight -1)));
		int xRegionEnd = (int)((dungeonRegion.RightEdge * (MapWidth -1)));
		int yRegionEnd = (int)((dungeonRegion.BottomEdge * (MapHeight -1)));
		int regionWidth = xRegionEnd - xRegionStart;
		int regionHeight = yRegionEnd - yRegionStart;
		
		int roomWidth = RandomValueBetween(Math.Min(MinIdealRoomSize, regionWidth), regionWdith);
		int roomHeight = RandomValueBetween(Math.Min(MinIdealRoomSize, regionHeight), regionHeight);
		
		int xRoomStart = xRegionStart + rand.Next(regionWidth - roomWidth);
		int yRoomStart = yRegionStart + rand.Next(regionHeight - roomHeight);
		
		PaintCellRectangle(xRoomStart, yRoomStart, xRoomStart + roomWidth, yRoomStart + roomHeight, new Cell_Wall(), true);
		PaintCellRectangle(xRoomStart + 1, yRoomStart + 1, xRoomStart + roomWidth - 1, yRoomStart + roomHeight -1, new Cell_Floor(), true);
	}
	public void PaintCellRectangle(int xStart, int yStart, int xEnd, int yEnd, Cell cell, bool forceDraw)
	{
	
		for(int y = yStart; y <= yEnd; y++)
			for(int x = xStart; x <= xEnd; x++)
		{
			if(forceDraw || Cells[x,y] == null || Cells[x,y].GetType() == typeof(Cell_Granite))
				cells[x,y] = cell;
		}
	}
}
